package socket

import (
	"errors"
	"github.com/gorilla/websocket"
	"sync"
)


type ConnectionWs struct{
	fd uint32
	wsConnect *websocket.Conn
	inChan chan []byte
	outChan chan []byte
	closeChan chan byte
	mq chan ChanMessage

	mutex sync.Mutex  // 对closeChan关闭上锁
	isClosed bool  // 防止closeChan被关闭多次
}

// 初始化连接
func InitWSConnection (wsConn *websocket.Conn, fd uint32, mq chan ChanMessage) (connection *ConnectionWs, err error) {
	connection = &ConnectionWs{
		fd : fd,
		wsConnect: wsConn,
		inChan: make(chan []byte, 1000),
		outChan: make(chan []byte, 1000),
		closeChan: make(chan byte, 1000),
		mq : mq,
	}

	// 启动读写协程
	go connection.readLoop()
	go connection.writeLoop()

	return
}

// 关闭
func (conn *ConnectionWs) Close() {
	// 线程安全， 可以多次调用
	conn.wsConnect.Close()
	// 利用标记，让closeChan只关闭一次
	conn.mutex.Lock()
	if !conn.isClosed {
		close(conn.closeChan)
		conn.isClosed = true
	}
	conn.mutex.Unlock()
}

// 写入消息
func (conn *ConnectionWs) WriteMessage(data []byte) (err error) {
	select {
		case conn.outChan <- data:
		case <-conn.closeChan:
			err = errors.New("connection is closed")
	}

	return
}

// 读循环
func (conn *ConnectionWs) readLoop() {
	var (
		data []byte
		err error
	)

	for {
		if _, data, err = conn.wsConnect.ReadMessage(); err != nil {
			goto ERR
		}
		chanMes := ChanMessage{
			Fd:   conn.fd,
			Data: data,
		}

		select {
			case conn.mq <- chanMes:
			case <- conn.closeChan:
				goto ERR
		}
	}
ERR:
	conn.Close()
}

// 写循环
func (conn *ConnectionWs) writeLoop() {
	var (
		data []byte
		err error
	)

	for {
		select {
			case data= <- conn.outChan:
			case <- conn.closeChan:
				goto ERR
		}
		if err = conn.wsConnect.WriteMessage(websocket.TextMessage, data); err != nil {
			goto ERR
		}
	}
ERR:
	conn.Close()
}